package dcpb.re.encrypt;


import dcpb.re.Cost;
import it.unisa.dia.gas.jpbc.Element;
import it.unisa.dia.gas.jpbc.Field;
import it.unisa.dia.gas.jpbc.Pairing;
import it.unisa.dia.gas.plaf.jpbc.field.curve.CurveElement;
import it.unisa.dia.gas.plaf.jpbc.field.z.ZrElement;
import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;


import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.AbstractMap.SimpleEntry;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public class Demo {

	public static long time1=0;
	public static long time2=0;
	public static void main(String[] args) {

		ProxyReEncrypt  d=new ProxyReEncrypt ();

		 byte[] message = null;// 要发送的信息
		 message="hello world".getBytes();
		int m=5,t=3;// 密钥分片
		SimpleEntry<PubParams,Element> retMap=d.setup();//CA 生成系统参数
		PubParams p=retMap.getKey();//公共参数
		d.save(p);//保存到文件



		int[] numbers={20,30,40,50,60};
		for(int j=0;j<numbers.length;j++) {
			long startTime = System.currentTimeMillis();    //获取开始时间
			Fabric f=new Fabric(p,m,t,retMap.getValue());
			List<Bob> bs = new ArrayList<>();
			try (Cost c = new Cost("keyGen")) {
				for (int i = 0; i < numbers[j]; i++) {
					bs.add(new Bob(p, t, f.KeyGen()));
				}
			}
			Alice a = new Alice(p, m, t);
			List<Element> users = f.getIDs();
			a.setReceivers(users);
			byte[] encryptedMessage;
			try (Cost c = new Cost("Enc")) {
				encryptedMessage=a.FileEncrypt(message);
			}
			Element A;// = f.setA(users);//获得重加密密钥
			SimpleEntry<List<Element>,List<Element>> xsAndYs;
			try (Cost c = new Cost("RkGen")) {
				A = f.setA(users);//获得重加密密钥
				a.RkGen(A);
			}
			List<Proxy> ps = new LinkedList<Proxy>();
			try (Cost c = new Cost("ReEnc")) {
				for (int i = 0; i < m; i++) {
					Proxy proxy = new Proxy(a.x_xsAndYs.getKey().get(i), a.x_xsAndYs.getValue().get(i),a.y_xsAndYs.getKey().get(i), a.y_xsAndYs.getValue().get(i));
					try {

						proxy.reEnc(a.content.getValue(), a.rkws.getKey());
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					ps.add(proxy);
				}
			}
			List<Element> xs = new LinkedList();
			List<Element> xs1=new LinkedList();
			List<Element> xtemps1 = new ArrayList<>(t);
			List<Element> xtemps2 = new ArrayList<>(t);
			for (Proxy pro : ps) {
				//xs.add((Element) pro.getC().get("x"));
				xs.add(pro.c31x_x);
				xs1.add(pro.c31y_x);
			}
			xtemps1=getX(xs,t,p);
			xtemps2=getX(xs1,t,p);



			try (Cost c11 = new Cost("Dec2")) {

				for (int i = 0; i < bs.size(); i++) {
					Bob b = bs.get(i);
					List<Element>  ys1 = new LinkedList();
					List<Element>  ys2 = new LinkedList();
					Map c = null;
					Element c31x,c31y;
					CurveElement c31= (CurveElement) p.G1.newZeroElement();
					for (Proxy pro : ps) {
						c = pro.getC();
						ys1.add(pro.c31x_y);
						ys2.add(pro.c31y_y);
					}
					//try (Cost rec = new Cost("recover2")){
						c31x = d.recover(p, xtemps1, ys1, t);
						c31y = d.recover(p, xtemps2, ys2, t);
						c31.setX(c31x);
						c31.setY(c31y);
					//}
					b.getRekey(ps.get(0).getC(),c31);//获得重加密数据
					b.getEncryptedMessage(encryptedMessage);//获得加密的文本数据
					//try (Cost rec = new Cost("dec222")) {
						b.dec(A);
					//}
				}
			}
			try (Cost c11 = new Cost("Dec1")){
				a.dec();
			}

			long endTime = System.currentTimeMillis();    //获取结束时间
			System.out.print((endTime - startTime) + ",\n");    //输出程序运行时间
		}


	}
	static List<Element> getX(List<Element> xs,int t,PubParams p){
		List<Element> xtemps = new ArrayList<>(t);
		try (Cost rec = new Cost("recover1")) {

			for (int i1 = 0; i1 < t; i1++) {
				Element xtemp = p.Zr.newOneElement();
				Element xi = xs.get(i1);
				for (int j1 = 0; j1 < t; j1++) {
					if (j1 == i1) continue;
					Element xj = xs.get(j1).duplicate();
					xtemp = xtemp.mul(xj.div(xj.duplicate().sub(xi)));
				}
				xtemps.add(xtemp);
			}
		}
		return xtemps;
	}
	
}